﻿#include "AssetSubsystem.h"

#include "AssetReader.h"
#include "AssetWriter.h"
#include "AssetObject.h"
#include "AssetHead.h"

#include "Object/NewObject.h"
#include "Object/FindObject.h"

#include "Serialize/BinarySerializer.h"
#include "Serialize/JsonSerializer.h"

#include "Containers/ReflectableMap.h"

#include "Output/Console.h"
#include "Misc/DebugMacros.h"

#include "Path/Paths.h"

#include "Texture/Texture2D.h"

#include "Object/Object.h"
#include "Object/RootObject.h"

#include "AssetObjectSerializer.h"

static RAssetSubsystem* GAssetSubsystem = nullptr;

void RAssetSubsystem::Initialize()
{
    GAssetSubsystem = this;

    AssetReader = new CAssetReader();
    AssetWriter = new CAssetWriter();


}

void RAssetSubsystem::Deinitialize()
{
    GAssetSubsystem = nullptr;

    delete AssetReader;
    AssetReader = nullptr;
    delete AssetWriter;
    AssetWriter = nullptr;
}

RAssetSubsystem* RAssetSubsystem::Get()
{
    return GAssetSubsystem;
}

RAssetSubsystemPtr RAssetSubsystem::GetInstance()
{
    return GAssetSubsystem;
}

void RAssetSubsystem::AddPackage(const SAssetPackage &InPackage)
{
    std::lock_guard<std::mutex> LockGuard(PackagesLock);
    Packages.Add(InPackage.Name, InPackage);
}

TVector<SAssetPackage> RAssetSubsystem::GetAllPackages() 
{
    std::lock_guard<std::mutex> LockGuard(PackagesLock);
    return Packages.Values();
}

SAssetPackage RAssetSubsystem::FindPackage(const CString &InPackageName)
{
    std::lock_guard<std::mutex> LockGuard(PackagesLock);
    return Packages[InPackageName];
}

void RAssetSubsystem::AsyncSaveAsset(
    const SAssetPath &AssetPath
    , RObjectPtr AssetMainObject
    , RObjectPtr EditInfoObject
    , TSharedObjectPtr<RTexture2D> Thumbnail
    , const TDelegate<void, SAssetHead> &OnSaveCompleted
    , TSharedObjectPtr<RAssetObject> InAssetObject
    , bool bBlockUntilFinished
    )
{

    SAssetHead AssetHead;
    AssetHead.AssetType= EditInfoObject.IsValid()? EAssetType::Editable : EAssetType::Minimal; 
    AssetHead.MainObjectClass=AssetMainObject->GetClass();
    AssetHead.AssetName=AssetPath.GetAssetName();

    //do main thread work;
    //1.找到所有要保存的主要对象
    TVector<RObjectPtr> MainObjects;
    {
        MainObjects.Add(AssetMainObject);

        //recursive find all children
        for(int32_t i=0;i<MainObjects.Num();i++)
        {
            auto Object=MainObjects[i];
            for(auto& Child:Object->GetChildren())
            {
                MainObjects.Add(Child);
            }
        }
    }


    //2.找到所有要保存的编辑信息对象
    TVector<RObjectPtr> AllEditInfoObjects;
    if(EditInfoObject)
    {
        AllEditInfoObjects.Add(EditInfoObject);

        //recursive find all children
        for(int32_t i=0;i<AllEditInfoObjects.Num();i++)
        {
            auto Object=AllEditInfoObjects[i];
            for(auto& Child:Object->GetChildren())
            {
                //exclude object that already in MainObjects
                if(MainObjects.Contains(Child))
                {
                    continue;
                }

                AllEditInfoObjects.Add(Child);
            }
        }

    }

    //3. 找到对其他资产的引用
    {
        TForwardForwardLinkedList<RObject *> ReferencedObjects;
        for(auto& Object:MainObjects)
        {
            Object->GetReferencedObjects(ReferencedObjects);
        }
        for(auto& Object:AllEditInfoObjects)
        {
            Object->GetReferencedObjects(ReferencedObjects);
        }

        for(auto& Object:ReferencedObjects)
        {
            if(MainObjects.Contains(Object) || AllEditInfoObjects.Contains(Object))
            {
                continue;
            }

            //添加外部对象列表
            AssetHead.ExternalObjects.Add(Object->GetPath());

            //添加外部资产列表
            auto AssetObject=RAssetObject::GetAssetObject(Object);
            if(AssetObject->bAlwaysInMemory)
            {
                continue;
            }
            const SAssetPath* AssetPath=AssetObject->GetAssetPath();
            assert(AssetPath&& "A referenced object do not belong into any asset, will not find it when deseralize asset" );
            AssetHead.Dependencies.AddUnique(*AssetPath);

        }
    }

    //4.create AssetObject
    TSharedObjectPtr<RAssetObject> AssetObject=InAssetObject;
    if(!AssetObject)
    {
        AssetObject=NewObject<RAssetObject>((RObject*)WH::GetRootObject());
        AssetObject->SetAssetPath(AssetPath);
    }
    else
    {
        assert(*AssetObject->GetAssetPath()==AssetPath && "AssetObject's path must be same as AssetPath");
    }
    
    AssetMainObject->SetOwner(AssetObject.Get());
    if(EditInfoObject)
    {
        EditInfoObject->SetOwner(AssetObject.Get());
    }

    AssetObject->MainObject=AssetMainObject;
    AssetObject->EditInfoObject=EditInfoObject;
    AssetObject->Thumbnail=Thumbnail;
    //AssetObject->DisplayName=DisplayName;    


    //1. convert everything to binary
    auto SerializeTask=WH::CreateAsyncTask<SAssetHead>([
        AssetHead
        ,MainObjects
        ,AllEditInfoObjects
        ,Thumbnail
        ,AssetObject
        ,AssetPath
        ](bool&) -> SAssetHead
    {
        SAssetHead FinalHead= AssetHead;

        TVector<RObjectPtr> AllObjects;
        AllObjects.Reserve(MainObjects.Num()+AllEditInfoObjects.Num());
        AllObjects.Append(MainObjects);
        AllObjects.Append(AllEditInfoObjects);

        FinalHead.InternalObjects.Reserve(AllObjects.Num());
        for(auto& Object:AllObjects)
        {
            FinalHead.InternalObjects.Add(Object->GetPath());
        }

        uint32_t FirstEditInfoObjectIndex=MainObjects.Num();
        //1.1 convert Mainobject  into binary
        TVector<uint8_t> MainObjectsData;
        std::shared_ptr<CBinarySerializer> BinarySerializer=
            std::make_shared<CBinarySerializer>(MainObjectsData);
        {
            //find owner object index
            TVector<int32_t> OwnerObjectIndices;
            for(auto& Object:MainObjects)
            {
                if(Object->GetOwner()==AssetObject)
                {
                    OwnerObjectIndices.Add(-1);
                }
                else
                {
                    auto Found=AllObjects.Find(Object->GetOwner());
                    OwnerObjectIndices.Add(Found.GetValue());
                }
            }

            //save  MainObjects 
            auto ObjectsJson= std::make_shared<CJsonVectorNode>();
            for(int i=0;i<MainObjects.Num();i++)
            {
                auto ObjectJson = std::make_shared<CJsonObjectNode>();
                ObjectJson->Add(U"Class", std::make_shared<CJsonStringNode>(AllObjects[i]->GetClass()->GetFullName()));
                ObjectJson->Add(U"Owner", std::make_shared<CJsonIntNode>(OwnerObjectIndices[i]));
                ObjectJson->Add(U"Name", std::make_shared<CJsonStringNode>(AllObjects[i]->GetNodeName()));
                ObjectJson->Add(U"BinaryOffset", std::make_shared<CJsonIntNode>(MainObjectsData.Num()));
                {
                    CJsonSerializer ObjectSerializer(
                        std::make_shared<CAssetObjectSerializer>(FinalHead)
                        ,BinarySerializer
                        );
                    ObjectJson->Add(U"Object", ObjectSerializer.SerializeToJson(AllObjects[i]));
                }
                ObjectsJson->Add(ObjectJson);
            }


            CString JsonString=CJsonUtils::ToString(ObjectsJson);

#if PrintSerializedJson
            WH::PrintLine(JsonString);
#endif
            FinalHead.MainObjectBinarySize=MainObjectsData.Num();
            *BinarySerializer<<JsonString;
        }

        //1.2 convert edit info object into binary
        TVector<uint8_t> EditInfoObjectsData;
        if(!AllEditInfoObjects.Empty())
        {
            //find owner object index
            TVector<int32_t> OwnerObjectIndices;
            for(auto& Object:AllEditInfoObjects)
            {
                if(Object->GetOwner()==AssetObject)
                {
                    OwnerObjectIndices.Add(-1);
                }
                else
                {
                    auto Found=AllObjects.Find(Object->GetOwner());
                    OwnerObjectIndices.Add(Found.GetValue());
                }
            }

            //save all edit info objects
            auto ObjectsJson = std::make_shared<CJsonVectorNode>();
            for(int i=0;i<AllEditInfoObjects.Num();i++)
            {
                auto ObjectJson = std::make_shared<CJsonObjectNode>();
                ObjectJson->Add(U"Class", std::make_shared<CJsonStringNode>(AllEditInfoObjects[i]->GetClass()->GetFullName()));
                ObjectJson->Add(U"Owner", std::make_shared<CJsonIntNode>(OwnerObjectIndices[i]));
                ObjectJson->Add(U"Name", std::make_shared<CJsonStringNode>(AllEditInfoObjects[i]->GetNodeName()));
                
                {
                    CJsonSerializer ObjectSerializer(std::make_shared<CAssetObjectSerializer>(FinalHead));
                    ObjectJson->Add(U"Object", ObjectSerializer.SerializeToJson(AllEditInfoObjects[i]));
                }
                ObjectsJson->Add(ObjectJson);                
            }

            CString JsonString=CJsonUtils::ToString(ObjectsJson);
#if PrintSerializedJson
            WH::PrintLine(JsonString);
#endif
            CBinarySerializer BinarySerializer(EditInfoObjectsData);
            BinarySerializer<<JsonString;
        }

        //1.3 convert thumbnail into binary
        TVector<uint8_t> ThumbnailData;
        if(Thumbnail)
        {
            RTexture2D::SaveToPNGFileData(Thumbnail,ThumbnailData);
        }

        //1.4 finish asset head and convert asset head into binary
        //SAssetHead FinalHead= AssetHead;
        {
            FinalHead.MainObjectSize=MainObjectsData.Num();
            FinalHead.ThumbnailSize=ThumbnailData.Num();
            FinalHead.EditInfoObjectSize=EditInfoObjectsData.Num();
        }
        TVector<uint8_t> HeadData=AnyThreadSaveAssetHead(FinalHead);

        //1.5 convert everything into final binary
        TVector<uint8_t> FinalBinary;
        {
            //save head size 
            CBinarySerializer BinarySerializer(FinalBinary);
            BinarySerializer<<(uint64_t)(HeadData.Num()+ sizeof(uint64_t) /*size of size*/  );

            FinalBinary.Append(HeadData);
            FinalBinary.Append(ThumbnailData);
            FinalBinary.Append(MainObjectsData);
            FinalBinary.Append(EditInfoObjectsData);
        }

        auto SaveTask=RAssetSubsystem::Get()
            ->GetAssetWriter()
            ->CreateAsyncWriteTask(FinalBinary,AssetPath,false);

        SaveTask->RunInThisThread();

        return FinalHead;
    });

    //2.invoke callback in main thread
    SerializeTask->ThenInMainThread<void>([OnSaveCompleted,SerializeTask](bool&)->void
        {
            OnSaveCompleted.ExecuteIfBound(SerializeTask->GetResult());
        }
    );

    //3.start task
    if(bBlockUntilFinished)
    {
        WH::BlockUntilFinished(SerializeTask);
    }
    else
    {
        SerializeTask->Start();
    }
 
}

void RAssetSubsystem::AsyncLoadAsset(
    const SAssetPath &AssetPath
    ,EAssetSection Sections
    ,TDelegate<void, SAssetLoadResult> OnLoaded
    ,TDelegate<void> OnLoadFailed
    )
{
    if(Sections==EAssetSection::Head)
    {
        //just load head

        auto LoadHeadDataTask=AssetReader->CreateAsyncReadTask(AssetPath,true);
        
        auto LoadFailedTask=LoadHeadDataTask->ThenInMainThreadIfFailed<void>(
            [OnLoadFailed](bool&)->void
            {
                OnLoadFailed.ExecuteIfBound();
            }
        );

        auto ParseTask=LoadHeadDataTask->ThenInThreadPool<SAssetHead>(
            [LoadHeadDataTask](bool &)->SAssetHead{
                return RAssetSubsystem::Get()->AnyThreadParseAssetHead(LoadHeadDataTask->GetResult());
            }
        );

        ParseTask->ThenInMainThread<void>(
            [OnLoaded,ParseTask](bool&)->void
            {
                SAssetLoadResult Result;
                Result.Head=ParseTask->GetResult();
                OnLoaded.ExecuteIfBound(Result);
            }
        );

        LoadHeadDataTask->Start();

        return;
    }

    // Find Or Create asset object
    TSharedObjectPtr<RAssetObject> AssetObject;
    {
        auto FoundObject=FindObject(RAssetObject::CreatePath(AssetPath));
        if(FoundObject)
        {
            AssetObject=FoundObject;

            if(Sections==EAssetSection::Thumbnail && AssetObject->Thumbnail)
            {
                SAssetLoadResult Result;
                Result.Thumbnail= AssetObject->Thumbnail;

                if(CAsyncSystem::IsInMainThread())
                {
                    OnLoaded.ExecuteIfBound(Result);
                    return;
                }
                else
                {
                    auto CallBack=WH::CreateMainThreadTask<void>([OnLoaded,Result](bool&)->void
                    {
                        OnLoaded.ExecuteIfBound(Result);
                    });
                    CallBack->Start();
                    return;
                }
            }
        }
        else
        {
            AssetObject=NewObject<RAssetObject>((RObject*)WH::GetRootObject());
            AssetObject->SetAssetPath(AssetPath);
        }
    }


    //load and whole asset into json
    auto LoadAssetDataTask=AssetReader->CreateAsyncReadTask(AssetPath,false);

    auto LoadFailedTask=LoadAssetDataTask->ThenInMainThreadIfFailed<void>(
        [OnLoadFailed](bool&)->void
        {
            OnLoadFailed.ExecuteIfBound();
        }
    );

    auto LoadAssetDataTaskFuture= LoadAssetDataTask->GetFuture();
    auto ParseTask=LoadAssetDataTask->ThenInThreadPool<SAssetLoadResult>(
        [LoadAssetDataTaskFuture,Sections,AssetPath,AssetObject,this](bool &)->SAssetLoadResult{

            SAssetLoadResult Result;
            
            auto& AssetData=LoadAssetDataTaskFuture.Get();


            SAssetHead Head= RAssetSubsystem::Get()->AnyThreadParseAssetHead(AssetData);
            Result.Head=Head;

            return this->ParseAsset(
                AssetData
                ,Sections
                ,AssetPath
                ,Head
                ,AssetObject
            );
        }
    );

    auto ParseTaskFuture=ParseTask->GetFuture();
    ParseTask->ThenInMainThread<void>([OnLoaded,ParseTaskFuture](bool&){
        OnLoaded.ExecuteIfBound(ParseTaskFuture.Get());
    });

    LoadAssetDataTask->Start();
}

void RAssetSubsystem::AsyncLoadAsset(const SAssetPath &AssetPath, const TVector<uint8_t> &AssetFileData, EAssetSection Sections, TDelegate<void, SAssetLoadResult> OnLoaded, TDelegate<void> OnLoadFailed)
{
    if(Sections==EAssetSection::Head)
    {
        //just load head
        auto ParseTask=WH::CreateAsyncTask<SAssetHead>(
            [AssetFileData](bool &)->SAssetHead{
                return RAssetSubsystem::Get()->AnyThreadParseAssetHead(AssetFileData);
            }
        );
        ParseTask->ThenInMainThread<void>(
            [OnLoaded,ParseTask](bool&)->void
            {
                SAssetLoadResult Result;
                Result.Head=ParseTask->GetResult();
                OnLoaded.ExecuteIfBound(Result);
            }
        );

        ParseTask->Start();

        return;
    }

    // Find Or Create asset object
    TSharedObjectPtr<RAssetObject> AssetObject;
    {
        auto FoundObject=FindObject(RAssetObject::CreatePath(AssetPath));
        if(FoundObject)
        {
            AssetObject=FoundObject;

            if(Sections==EAssetSection::Thumbnail && AssetObject->Thumbnail)
            {
                SAssetLoadResult Result;
                Result.Thumbnail= AssetObject->Thumbnail;

                if(CAsyncSystem::IsInMainThread())
                {
                    OnLoaded.ExecuteIfBound(Result);
                    return;
                }
                else
                {
                    auto CallBack=WH::CreateMainThreadTask<void>([OnLoaded,Result](bool&)->void
                    {
                        OnLoaded.ExecuteIfBound(Result);
                    });
                    CallBack->Start();
                    return;
                }
            }
        }
        else
        {
            AssetObject=NewObject<RAssetObject>((RObject*)WH::GetRootObject());
            AssetObject->SetAssetPath(AssetPath);
        }
    }


    //load and whole asset into json
    auto ParseTask=WH::CreateAsyncTask<SAssetLoadResult>(
        [AssetFileData,Sections,AssetPath,AssetObject,this](bool &)->SAssetLoadResult{

            SAssetHead Head= RAssetSubsystem::Get()->AnyThreadParseAssetHead(AssetFileData);
            return this->ParseAsset(
                AssetFileData
                ,Sections
                ,AssetPath
                ,Head
                ,AssetObject
            );
        }
    );

    auto ParseTaskFuture=ParseTask->GetFuture();
    ParseTask->ThenInMainThread<void>([OnLoaded,ParseTaskFuture](bool&){
        OnLoaded.ExecuteIfBound(ParseTaskFuture.Get());
    });

    ParseTask->Start();    
}

TSharedObjectPtr<RObject> RAssetSubsystem::LoadAsset(const SAssetPath &InAssetPath)
{
    assert(CAsyncSystem::IsInMainThread()&& "this function designed to run in main thread");

    RAssetSubsystem* AssetSubsystem=RAssetSubsystem::Get();

    bool bDone=false;
    TOptional<SAssetLoadResult> Result;

    AssetSubsystem->AsyncLoadAsset(
        InAssetPath
        ,EAssetSection::MainObject
        ,[&Result,&bDone](const SAssetLoadResult& LoadResult)
        {
            Result=LoadResult;
            bDone=true;
        }
        ,[&bDone]()
        {
            //load failed
            bDone=true;
        }

        );

    //block until loaded
    while(!bDone)
    {
        CAsyncSystem::Get()->DoMainThreadWork();
    }

    if(!Result.HasValue())
    {
        return nullptr;
    }

    return Result.GetValue().MainObject;
}

TOptional<SAssetPath> RAssetSubsystem::LoadAssetPath(CString PackageName,const SPath& AssetFilePath)
{
    auto OptionalHead=LoadAssetHead(AssetFilePath);
    if(!OptionalHead.HasValue())
    {
        //文件头读取失败或者文件内容为空
        return TOptional<SAssetPath>();
    }

    return CreateAssetPath(
        OptionalHead.GetValue().MainObjectClass
        ,PackageName
        ,AssetFilePath
    );
    
}

TOptional<SAssetHead> RAssetSubsystem::LoadAssetHead(const SPath &AssetFilePath)
{
    auto AssetFileTask=
        AssetReader
        ->CreateAsyncReadTask(AssetFilePath,true);
    
    if(!AssetFileTask->RunInThisThread())
    {
        //文件头读取失败或者文件内容为空
        return TOptional<SAssetHead>();
    }

    auto& HeadData=AssetFileTask->GetResult();

    return AnyThreadParseAssetHead(HeadData);
}

SAssetPath RAssetSubsystem::CreateAssetPath(CClass *InAssetType, const CString &InRegisteredPackageName, const SPath &AssetFilePath)
{
    SAssetPackage Package=FindPackage(InRegisteredPackageName);
    CString AssetName=AssetFilePath.GetBaseFileName();
    CString AssetRelativePath=SAssetPath::AbstractFolderPathInPackage(
        Package.Path
        ,AssetFilePath
    );
    return SAssetPath(
        InAssetType,
        InRegisteredPackageName
        ,AssetRelativePath
        ,AssetName
    );
}


TSharedObjectPtr<RObject> RAssetSubsystem::LoadAsset(
    const TVector<uint8_t> &InAssetFileData
    , const SAssetPackage &InPackage
    , const CString &InAssetRelativePathToPackage)
{
    auto Head=RAssetSubsystem::Get()->AnyThreadParseAssetHead(InAssetFileData);
    SAssetPath AssetPath= Head.CreateAssetPath(
        InPackage.Name
        ,InAssetRelativePathToPackage
    );

    auto OptionalResult=LoadAssetWithFileData(
        InAssetFileData
        ,AssetPath
        ,EAssetSection::MainObject);

    return OptionalResult.GetValue().MainObject;

}

TTuple<TSharedObjectPtr<RObject>, TSharedObjectPtr<RObject>> RAssetSubsystem::LoadAssetWithEditInfo(
    const TVector<uint8_t> &InAssetFileData
    , const SAssetPackage &InPackage
    , const CString &InAssetRelativePathToPackage)
{
    auto Head=RAssetSubsystem::Get()->AnyThreadParseAssetHead(InAssetFileData);
    SAssetPath AssetPath= Head.CreateAssetPath(
        InPackage.Name
        ,InAssetRelativePathToPackage
    );

    auto OptionalResult=LoadAssetWithFileData(
        InAssetFileData
        ,AssetPath
        ,EAssetSection::MainObjectAndEditInfoObject);

    if(!OptionalResult.HasValue())
    {
        //加载失败
        return TTuple<TSharedObjectPtr<RObject>,TSharedObjectPtr<RObject>>();
    }

    auto ResultValue=OptionalResult.GetValue();
    return WH::MakeTuple(ResultValue.MainObject,ResultValue.EditInfoObject);
}

TOptional<SAssetLoadResult> RAssetSubsystem::LoadAsset(
    const SAssetPath &AssetPath
    , EAssetSection SectionsToLoad)
{
    assert(CAsyncSystem::IsInMainThread()&& "this function designed to run in main thread");

    RAssetSubsystem* AssetSubsystem=RAssetSubsystem::Get();

    bool bDone=false;
    TOptional<SAssetLoadResult> Result;

    AssetSubsystem->AsyncLoadAsset(
        AssetPath
        ,SectionsToLoad
        ,[&Result,&bDone](const SAssetLoadResult& LoadResult)
        {
            Result=LoadResult;
            bDone=true;
        }
        ,[&bDone]()
        {
            //load failed
            bDone=true;
        }

        );

    //block until loaded
    while(!bDone)
    {
        CAsyncSystem::Get()->DoMainThreadWork();
    }

    return Result;
}

TOptional<SAssetLoadResult> RAssetSubsystem::LoadAssetWithFileData(const TVector<uint8_t> &InAssetFileData, const SAssetPath &AssetPath, EAssetSection SectionsToLoad)
{
    assert(CAsyncSystem::IsInMainThread()&& "this function designed to run in main thread");

    RAssetSubsystem* AssetSubsystem=RAssetSubsystem::Get();

    bool bDone=false;
    TOptional<SAssetLoadResult> Result;

    AssetSubsystem->AsyncLoadAsset(
        AssetPath
        ,InAssetFileData
        ,SectionsToLoad
        ,[&Result,&bDone](const SAssetLoadResult& LoadResult)
        {
            Result=LoadResult;
            bDone=true;
        }
        ,[&bDone]()
        {
            //load failed
            bDone=true;
        }

        );

    //block until loaded
    while(!bDone)
    {
        CAsyncSystem::Get()->DoMainThreadWork();
    }

    return Result;
}

void RAssetSubsystem::AsyncResaveLoadedAsset(RObjectPtr AssetMainObject, RObjectPtr EditInfoObject, TSharedObjectPtr<RTexture2D> Thumbnail, const TDelegate<void, SAssetHead> &OnSaveCompleted)
{
    //find former asset object
    RAssetObjectPtr AssetObject;
    {
        RObjectPtr CurrentObject=AssetMainObject;
        while(true)
        {
            if(CurrentObject->IsA<RAssetObject>())
            {
                AssetObject=CurrentObject;
                break;
            }
            CurrentObject=CurrentObject->GetOwner();

            assert(CurrentObject&& "Cant find asset object");
        }
    }

    AsyncSaveAsset(
        *AssetObject->GetAssetPath()
        ,AssetMainObject
        ,EditInfoObject
        ,Thumbnail
        ,OnSaveCompleted
        ,AssetObject
    );
}

SAssetHead RAssetSubsystem::ResaveLoadedAsset(RObjectPtr AssetMainObject, RObjectPtr EditInfoObject, TSharedObjectPtr<RTexture2D> Thumbnail)
{
    assert(CAsyncSystem::IsInMainThread()&& "this function designed to run in main thread");

    TOptional<SAssetHead> AssetHead;

    AsyncResaveLoadedAsset(
        AssetMainObject
        ,EditInfoObject
        ,Thumbnail
        ,[&AssetHead](const SAssetHead& InAssetHead)
        {
            AssetHead=InAssetHead;
        }
    );

    while(!AssetHead.HasValue())
    {
        CAsyncSystem::Get()->DoMainThreadWork();
    }

    return AssetHead.GetValue();
}

void RAssetSubsystem::AsyncImportObject(
    RObjectPtr InObject
    , RObjectPtr InEditInfoObject
    , TSharedObjectPtr<RTexture2D> InThumbnail
    , const CString &InPackageName
    , const CString &InQueryFolderRelativePath
    , const TDelegate<void, TOptional<CString>
    , SAssetPath, SAssetHead> &OnFinished)
{
  
    auto CreateAssetPathTask= WH::CreateAsyncTask<
        TTuple<SAssetPath,CString /*DisplayName*/>
        >(
        [this,InPackageName,InQueryFolderRelativePath,InObject,OnFinished](bool & bSucceed)
            ->TTuple<SAssetPath,CString /*DisplayName*/>
        {
            auto Task= this->AssetWriter->CreateAsyncCreateAssetPathTask(
                InObject->GetClass()
                ,InPackageName
                ,InQueryFolderRelativePath
                ,InObject->GetNodeName()
            );

            bool Succeed=Task->RunInThisThread();
            if(!Succeed)
            {
                OnFinished.ExecuteIfBound(Task->GetResult().First.GetValue(),SAssetPath(),SAssetHead());

                bSucceed=false;
                return WH::MakeTuple(SAssetPath(),CString());
            }

            return WH::MakeTuple(Task->GetResult().Second,Task->GetResult().Third);
        
        }
    );

    auto SaveAssetTask=CreateAssetPathTask->ThenInThreadPool<void>(
        [this,InObject,InEditInfoObject,InThumbnail,OnFinished,CreateAssetPathTask](bool& bSucceed)->void
        {
            auto& PathResult=CreateAssetPathTask->GetResult();

            this->AsyncSaveAsset(
                PathResult.First
                ,InObject
                ,InEditInfoObject
                ,InThumbnail
                ,TDelegate<void,SAssetHead>::Create(
                    [OnFinished,PathResult](const SAssetHead& InAssetHead){
    
                    OnFinished.ExecuteIfBound(TOptional<CString>(),PathResult.First,InAssetHead);
                })
            );
        }
    );

    CreateAssetPathTask->Start();
}

SImportResult RAssetSubsystem::ImportObject(
    RObjectPtr InObject
    , RObjectPtr InEditInfoObject
    ,TSharedObjectPtr<RTexture2D> InThumbnail
    , const CString &InPackageName
    , const CString &InQueryFolderRelativePath)
{
    assert(CAsyncSystem::IsInMainThread()&& "this function designed to run in main thread");

    SImportResult Result;
    bool bFinished=false;
    bool bSucceed=false;

    AsyncImportObject(
        InObject
        ,InEditInfoObject
        ,InThumbnail
        ,InPackageName
        ,InQueryFolderRelativePath
        ,[&Result,&bSucceed,&bFinished](TOptional<CString> InErrorMessage, SAssetPath InAssetPath, SAssetHead InAssetHead)
        {
            bFinished=true;
            if(InErrorMessage.HasValue())
            {
                bSucceed=false;
                WH::PrintLine(InErrorMessage.GetValue());
            }
            else
            {
                bSucceed=true;
                Result.AssetPath=InAssetPath;
                Result.Head=InAssetHead;
            }

        }
    );

    while(!bFinished)
    {
        CAsyncSystem::Get()->DoMainThreadWork();
    }

    return Result;
}

SAssetHead RAssetSubsystem::AnyThreadParseAssetHead(const TVector<uint8_t> &InAssetFileData)
{
    assert(!InAssetFileData.Empty());

    CBinaryDeserializer BinaryDeserializer(InAssetFileData);

    //1. load head size
    uint64_t HeadSize;
    {
        BinaryDeserializer>>HeadSize;
    }

    //2. load head content

    CString JsonString;
    BinaryDeserializer>>JsonString;

    return AnyThreadParseAssetHeadFromJson(JsonString,HeadSize);
}


SAssetLoadResult RAssetSubsystem::ParseAsset(
    const TVector<uint8_t> &AssetData,
    EAssetSection Sections,
    const SAssetPath &AssetPath,
    const SAssetHead &Head,
    TSharedObjectPtr<RAssetObject> AssetObject)
{
    SAssetLoadResult Result;
    Result.Head=Head;

    bool LoadMainObject= (uint64_t)Sections & (uint64_t)EAssetSection::MainObject && Head.MainObjectSize>0;
    bool LoadEditInfoObject= (uint64_t)Sections & (uint64_t)EAssetSection::EditInfoObject && Head.EditInfoObjectSize>0;

    if(LoadMainObject || LoadEditInfoObject)
    {
        //1. 找到所有依赖的资产
        TVector<SAssetPath> AllDependencies;
        TVector<SAssetHead> AllDependenciesHead;

        AnyThreadRecursiveFindDependencies(
            Head
            ,AllDependencies
            ,AllDependenciesHead);
        
        //2.加载所有依赖资产的对象，确保它们在加载本资产对象之前存活
        TVector<RObjectPtr> AllDependencyObjects; 

        for(int DependencyIndex=AllDependencies.Num()-1;DependencyIndex>=0;DependencyIndex--)
        {
            //2.0 Load dependency asset
            auto LoadDependencyTask=RAssetSubsystem::Get()->
                GetAssetReader()->
            CreateAsyncReadTask(AllDependencies[DependencyIndex],false);
            LoadDependencyTask->RunInThisThread();
            auto DependencyData=LoadDependencyTask->GetResult();

            //2.1 Create asset object
            TSharedObjectPtr<RAssetObject> DependencyAssetObject;
            {
                auto FoundObject=FindObject(RAssetObject::CreatePath(AllDependencies[DependencyIndex]));
                if(FoundObject)
                {
                    DependencyAssetObject=FoundObject;
                }
                else
                {
                    DependencyAssetObject=NewObject<RAssetObject>((RObject*)WH::GetRootObject());
                    DependencyAssetObject->SetAssetPath(AllDependencies[DependencyIndex]);
                }
            }
        
            //2.2 find main object section and load to json object
            std::shared_ptr<CJsonVectorNode> ObjectsJsonList;
            {
                TVector<uint8_t> MainObjectData= DependencyData.Slice(
                        AllDependenciesHead[DependencyIndex].GetMainObjectOffset()
                        ,AllDependenciesHead[DependencyIndex].MainObjectSize+AllDependenciesHead[DependencyIndex].GetMainObjectOffset());

                CBinaryDeserializer BinaryDeserializer(DependencyData,AllDependenciesHead[DependencyIndex].GetMainObjectOffset());

                //skip binary data of main object section
                BinaryDeserializer.TakeOut(AllDependenciesHead[DependencyIndex].MainObjectBinarySize);
                
                CString MainObjectJsonString;
                BinaryDeserializer>>MainObjectJsonString;
                ObjectsJsonList = std::static_pointer_cast<CJsonVectorNode>(CJsonUtils::Parse(MainObjectJsonString));                    
            }

            //2.3 create all objects without fill data
            TVector<RObjectPtr> AllMainObjects;
            AllMainObjects.Reserve(ObjectsJsonList->Num());

            for(auto& ObjectJson:ObjectsJsonList->GetNodes())
            {
                std::shared_ptr<CJsonObjectNode> ObjectJsonDict = ObjectJson->ToObject();
                auto ClassString=ObjectJsonDict->Get(U"Class")->ToString()->GetValue();
                CClass* Class=nullptr;
                {
                    CType* Type= CType::FindType(ClassString);
                    assert(Type&& Type->IsClassType());
                    Class=reinterpret_cast<CClass*>(Type);
                }

                CString Name = ObjectJsonDict->Get(U"Name")->ToString()->GetValue();
                RObjectPtr Owner;
                {
                    int32_t OwnerIndex=ObjectJsonDict->Get(U"Owner")->ToInt()->GetValue();
                    if(OwnerIndex==-1)
                    {
                        Owner=DependencyAssetObject;
                    }
                    else
                    {
                        Owner=AllMainObjects[OwnerIndex];
                    }
                }

                RObjectPtr Object= Owner->FindChild(Name);
                if(!Object)
                {
                    Object=NewObjectFirstStage(Class,Owner.Get());
                    Object->SetNodeName(Name);
                }
                
                AllMainObjects.Add(Object);
            }

            //2.4 fill data
            for(int i=0;i<ObjectsJsonList->Num();i++)
            {   
                RObjectPtr Object=AllMainObjects[i];
                if(Object->GetObjectHead()->IsTotallyInitialized())
                {
                    //object is already loaded, ignore it
                    continue;
                }

                std::shared_ptr<CJsonObjectNode> ObjectJsonDict = ObjectsJsonList->Get(i)->ToObject();
                
                uint64_t ObjectBinaryOffset=
                    AllDependenciesHead[DependencyIndex].GetMainObjectOffset()+
                    ObjectJsonDict->Get(U"BinaryOffset")->ToInt()->GetValue();
                
                std::shared_ptr<CBinaryDeserializer> ObjectBinaryDeserializer=
                    std::make_shared<CBinaryDeserializer>(DependencyData,ObjectBinaryOffset);

                
                {
                    CJsonDeserializer ObjectDeserializer(std::make_shared<CAssetObjectSerializer>(AllDependenciesHead[DependencyIndex]),ObjectBinaryDeserializer);
                    ObjectDeserializer.DeserializeFromJson(Object,ObjectJsonDict->Get(U"Object"));
                }
            }

            //2.5 invoke PostLoadFromAsset() for all objects
            for(int ObjectIndex= AllMainObjects.Num()-1;ObjectIndex>=0;ObjectIndex--)
            {
                if(AllMainObjects[ObjectIndex]->GetObjectHead()->IsTotallyInitialized())
                {
                    //object is already loaded, ignore it
                    continue;
                }

                AllMainObjects[ObjectIndex]->PostLoadFromAsset();
                AllMainObjects[ObjectIndex]->GetObjectHead()->MarkSecondStageFinished();
            }

            DependencyAssetObject->MainObject=AllMainObjects[0];

            AllDependencyObjects.Append(AllMainObjects);
        }
        
        //3.load main object and edit info object in  this asset
        //auto AssetData=LoadAssetDataTask->GetResult();



        //3.2 find main object section and load to json object
        std::shared_ptr<CJsonVectorNode> MainObjectsJsonList;
        {
            // TVector<uint8_t> MainObjectData= AssetData.Slice(
            //         Head.GetMainObjectOffset()
            //         ,Head.MainObjectSize +Head.GetMainObjectOffset() );
            
            CBinaryDeserializer BinaryDeserializer(AssetData,Head.GetMainObjectOffset());

            //skip binary data of main object section
            BinaryDeserializer.TakeOut(Head.MainObjectBinarySize);

            CString MainObjectJsonString;
            BinaryDeserializer>>MainObjectJsonString;

            MainObjectsJsonList = CJsonUtils::Parse(MainObjectJsonString)->ToList();
        }

        //3.3 create all objects without fill data
        TVector<RObjectPtr> AllMainObjects;
        AllMainObjects.Reserve(MainObjectsJsonList->Num());
        
        for(auto& ObjectJson:MainObjectsJsonList->GetNodes())
        {
            std::shared_ptr<CJsonObjectNode> ObjectJsonDict = ObjectJson->ToObject();
            auto ClassString=ObjectJsonDict->Get(U"Class")->ToString()->GetValue();
            CClass* Class=nullptr;
            {
                CType* Type= CType::FindType(ClassString);
                assert(Type&& Type->IsClassType());
                Class=reinterpret_cast<CClass*>(Type);
            }

            CString Name = ObjectJsonDict->Get(U"Name")->ToString()->GetValue();
            RObjectPtr Owner;
            {
                int32_t OwnerIndex=ObjectJsonDict->Get(U"Owner")->ToInt()->GetValue();
                if(OwnerIndex==-1)
                {
                    Owner=AssetObject;
                }
                else
                {
                    Owner=AllMainObjects[OwnerIndex];
                }
            }

            RObjectPtr Object= Owner->FindChild(Name);
            if(!Object)
            {
                Object=NewObjectFirstStage(Class,Owner.Get());
                Object->SetNodeName(Name);
            }
            
            AllMainObjects.Add(Object);
        }

        //3.4 fill data
        for(int i=0;i<MainObjectsJsonList->Num();i++)
        {
            RObjectPtr Object=AllMainObjects[i];
            if(Object->GetObjectHead()->IsTotallyInitialized())
            {
                //object is already loaded, ignore it
                continue;
            }


            std::shared_ptr<CJsonObjectNode> ObjectJsonDict = MainObjectsJsonList->Get(i)->ToObject();
            
            uint64_t ObjectBinaryOffset=
                Head.GetMainObjectOffset()+
                ObjectJsonDict->Get(U"BinaryOffset")->ToInt()->GetValue();

            std::shared_ptr<CBinaryDeserializer> ObjectBinaryDeserializer=
                std::make_shared<CBinaryDeserializer>(AssetData,ObjectBinaryOffset);
            
            
            {
                CJsonDeserializer ObjectDeserializer(std::make_shared<CAssetObjectSerializer>(Head),ObjectBinaryDeserializer);
                ObjectDeserializer.DeserializeFromJson(Object,ObjectJsonDict->Get(U"Object"));
            }
        }

        //3.5 invoke PostLoadFromAsset() for all objects
        for(int ObjectIndex= AllMainObjects.Num()-1;ObjectIndex>=0;ObjectIndex--)
        {
            if(AllMainObjects[ObjectIndex]->GetObjectHead()->IsTotallyInitialized())
            {
                //object is already loaded, ignore it
                continue;
            }

            AllMainObjects[ObjectIndex]->PostLoadFromAsset();
            AllMainObjects[ObjectIndex]->GetObjectHead()->MarkSecondStageFinished();
        }

        AssetObject->MainObject=AllMainObjects[0];
        Result.MainObject=AllMainObjects[0];

        //3.6 load edit info object if required
        if(LoadEditInfoObject)
        {
            //do the same thing as load main object

            //3.6.1 find edit info object section and load to json object
            std::shared_ptr<CJsonVectorNode> EditInfoObjectsJsonList;
            {
                TVector<uint8_t> EditInfoObjectData= AssetData.Slice(
                        Head.GetEditInfoObjectOffset()
                        ,Head.EditInfoObjectSize + Head.GetEditInfoObjectOffset() );
                
                CBinaryDeserializer BinaryDeserializer(EditInfoObjectData);
                CString EditInfoObjectJsonString;
                BinaryDeserializer>>EditInfoObjectJsonString;

                EditInfoObjectsJsonList = CJsonUtils::Parse(EditInfoObjectJsonString)->ToList();
            }

            //3.6.2 create all objects without fill data
            TVector<RObjectPtr> AllEditInfoObjects;
            AllEditInfoObjects.Reserve(EditInfoObjectsJsonList->Num());

            for(auto& ObjectJson:EditInfoObjectsJsonList->GetNodes())
            {
                std::shared_ptr<CJsonObjectNode> ObjectJsonDict = ObjectJson->ToObject();
                auto ClassString=ObjectJsonDict->Get(U"Class")->ToString()->GetValue();
                CClass* Class=nullptr;
                {
                    CType* Type= CType::FindType(ClassString);
                    assert(Type&& Type->IsClassType());
                    Class=reinterpret_cast<CClass*>(Type);
                }

                CString Name = ObjectJsonDict->Get(U"Name")->ToString()->GetValue();
                RObjectPtr Owner;
                {
                    int32_t OwnerIndex=ObjectJsonDict->Get(U"Owner")->ToInt()->GetValue();
                    if(OwnerIndex==-1)
                    {
                        Owner=AssetObject;
                    }
                    else
                    {
                        if(AllMainObjects.Num()> OwnerIndex)
                        {
                            Owner=AllMainObjects[OwnerIndex];
                        }
                        else
                        {
                            Owner=AllEditInfoObjects[OwnerIndex-AllMainObjects.Num()];
                        }
                    }
                }

                RObjectPtr Object= Owner->FindChild(Name);
                if(!Object)
                {
                    Object=NewObjectFirstStage(Class,Owner.Get());
                    Object->SetNodeName(Name);
                }
                
                AllEditInfoObjects.Add(Object);
            }

            //3.6.3 fill data
            for(int i=0;i<EditInfoObjectsJsonList->Num();i++)
            {
                RObjectPtr Object=AllEditInfoObjects[i];
                if(Object->GetObjectHead()->IsTotallyInitialized())
                {
                    //object is already loaded, ignore it
                    continue;
                }


                std::shared_ptr<CJsonObjectNode> ObjectJsonDict = EditInfoObjectsJsonList->Get(i)->ToObject();
                {
                    CJsonDeserializer ObjectDeserializer(std::make_shared<CAssetObjectSerializer>(Head));
                    ObjectDeserializer.DeserializeFromJson(Object,ObjectJsonDict->Get(U"Object"));
                }
            }

            //3.6.4 invoke PostLoadFromAsset() for all objects
            for(int ObjectIndex= AllEditInfoObjects.Num()-1;ObjectIndex>=0;ObjectIndex--)
            {
                if(AllEditInfoObjects[ObjectIndex]->GetObjectHead()->IsTotallyInitialized())
                {
                    //object is already loaded, ignore it
                    continue;
                }

                AllEditInfoObjects[ObjectIndex]->PostLoadFromAsset();
                AllEditInfoObjects[ObjectIndex]->GetObjectHead()->MarkSecondStageFinished();
            }

            AssetObject->EditInfoObject=AllEditInfoObjects[0];
            Result.EditInfoObject=AllEditInfoObjects[0];
        }


    }

    if((uint64_t)Sections & (uint64_t)EAssetSection::Thumbnail 
        && Head.ThumbnailSize>0 )
    {
        //check is thumbnail is loaded
        if(AssetObject->Thumbnail)
        {
            Result.Thumbnail=AssetObject->Thumbnail;
        }
        else
        {
            //load thumbnail
            TVector<uint8_t> ThumbnailData= AssetData.Slice(
                    Head.GetThumbnailOffset()
                    ,Head.ThumbnailSize+  Head.GetThumbnailOffset() );
            auto Thumbnail = RTexture2D::CreateFromPNGFileData(ThumbnailData,AssetObject.Get());
            Thumbnail->SetNodeName(U"EngineEditorThumbnail");
            //TODO make sure thumbnail name is unique and not conflict with other object

            Result.Thumbnail=Thumbnail;
            AssetObject->Thumbnail=Thumbnail;
        }
    }

    return Result;
}

void RAssetSubsystem::AnyThreadRecursiveFindDependencies(
    const SAssetHead &InHead
    , TVector<SAssetPath> &OutDependencies
    ,TVector<SAssetHead>& OutDependencyHeads
    )
{
    for(auto& Dependency:InHead.Dependencies)
    {
        if(OutDependencies.Contains(Dependency))
        {
            continue;
        }

        OutDependencies.Add(Dependency);

        auto LoadDependencyTask=RAssetSubsystem::Get()->
                    GetAssetReader()->
                CreateAsyncReadTask(Dependency,true);
        LoadDependencyTask->RunInThisThread();
        auto DependencyHeadData=LoadDependencyTask->GetResult();

        SAssetHead DependencyHead= RAssetSubsystem::Get()->AnyThreadParseAssetHead(DependencyHeadData);
        OutDependencyHeads.Add(DependencyHead);

        AnyThreadRecursiveFindDependencies(DependencyHead,OutDependencies,OutDependencyHeads);
    }
}

SAssetHead RAssetSubsystem::AnyThreadParseAssetHeadFromJson(const CString &HeadJson,uint64_t InHeadSize)
{
    //2. load head content
    SAssetHead AssetHead;
    AssetHead.HeadSize=InHeadSize;
    {
        std::shared_ptr<CJsonObjectNode> HeadContentJson = CJsonUtils::Parse(HeadJson)->ToObject() ;
        AssetHead.AssetType = (EAssetType)HeadContentJson->Get(U"AssetType")->ToInt()->GetValue();
        AssetHead.AssetName= HeadContentJson->Get(U"AssetName")->ToString()->GetValue();
        if(HeadContentJson->Contains(U"MainObjectsSize"))
        {
            AssetHead.MainObjectSize=HeadContentJson->Get(U"MainObjectsSize")->ToInt()->GetValue();
        }
        if(HeadContentJson->Contains(U"MainObjectsBinarySize"))
        {
            AssetHead.MainObjectBinarySize=HeadContentJson->Get(U"MainObjectsBinarySize")->ToInt()->GetValue();
        }

        if(HeadContentJson->Contains(U"ThumbnailSize"))
        {
            AssetHead.ThumbnailSize=HeadContentJson->Get(U"ThumbnailSize")->ToInt()->GetValue();
        }

        if(HeadContentJson->Contains(U"EditInfoObjectsSize"))
        {
            AssetHead.EditInfoObjectSize=HeadContentJson->Get(U"EditInfoObjectsSize")->ToInt()->GetValue();
        }     
        
        {
            CString ClassName= HeadContentJson->Get(U"MainObjectClass")->ToString()->GetValue();
            AssetHead.MainObjectClass  = reinterpret_cast<CClass*>(CType::FindType(ClassName));
            assert(AssetHead.MainObjectClass);
        }

        {
            std::shared_ptr<CJsonVectorNode> DependenciesJson = HeadContentJson->Get(U"Dependencies")->ToList();
            for(auto& DependencyJson:DependenciesJson->GetNodes())
            {
                AssetHead.Dependencies.Add(SAssetPath(DependencyJson->ToString()->GetValue()));
            }
        }

        {
            std::shared_ptr<CJsonVectorNode> ExternalObjectsJson = HeadContentJson->Get(U"ExternalObjects")->ToList();
            for(auto& ExternalObjectJson:ExternalObjectsJson->GetNodes())
            {
                AssetHead.ExternalObjects.Add(ExternalObjectJson->ToString()->GetValue());
            }
        }

        {
            std::shared_ptr<CJsonVectorNode> InternalObjectsJson = HeadContentJson->Get(U"InternalObjects")->ToList();
            for(auto& InternalObjectJson:InternalObjectsJson->GetNodes())
            {
                AssetHead.InternalObjects.Add(InternalObjectJson->ToString()->GetValue());
            }
        }
    }

    return AssetHead;
}

TVector<uint8_t> RAssetSubsystem::AnyThreadSaveAssetHead(const SAssetHead &InHead)
{
    TVector<uint8_t> Result;
    {
        auto HeadContentJson = std::make_shared<CJsonObjectNode>();  

        HeadContentJson->Add(U"MainObjectClass",std::make_shared<CJsonStringNode>(InHead.MainObjectClass->GetFullName()));
        HeadContentJson->Add(U"AssetType",std::make_shared<CJsonIntNode>((int64_t)InHead.AssetType));
        HeadContentJson->Add(U"AssetName", std::make_shared<CJsonStringNode>(InHead.AssetName));

        HeadContentJson->Add(U"MainObjectsSize",std::make_shared<CJsonIntNode>(InHead.MainObjectSize));
        HeadContentJson->Add(U"MainObjectsBinarySize",std::make_shared<CJsonIntNode>(InHead.MainObjectBinarySize));
        
        HeadContentJson->Add(U"ThumbnailSize",std::make_shared<CJsonIntNode>(InHead.ThumbnailSize));
        HeadContentJson->Add(U"EditInfoObjectsSize",std::make_shared<CJsonIntNode>(InHead.EditInfoObjectSize));
        
        
        std::shared_ptr<CJsonVectorNode> DependenciesJson = std::make_shared<CJsonVectorNode>();
        for(auto& Dependency:InHead.Dependencies)
        {
            DependenciesJson->Add(std::make_shared<CJsonStringNode>(Dependency.ToString()));
        }
        HeadContentJson->Add(U"Dependencies", DependenciesJson);

        //save external objects        
        std::shared_ptr<CJsonVectorNode> ExternalObjectsJson = std::make_shared<CJsonVectorNode>();
        for(auto& Object:InHead.ExternalObjects)
        {
            ExternalObjectsJson->Add(std::make_shared<CJsonStringNode>(Object));
        }
        HeadContentJson->Add(U"ExternalObjects", ExternalObjectsJson);

        //save internal objects
        std::shared_ptr<CJsonVectorNode> InternalObjectsJson = std::make_shared<CJsonVectorNode>();
        for(auto& Object:InHead.InternalObjects)
        {
            InternalObjectsJson->Add(std::make_shared<CJsonStringNode>(Object));
        } 
        HeadContentJson->Add(U"InternalObjects", InternalObjectsJson);

    
        CString JsonString=CJsonUtils::ToString(HeadContentJson);
        CBinarySerializer BinarySerializer(Result);
        BinarySerializer<<JsonString;
    }

    return Result;
}

uint64_t RAssetSubsystem::ReplaceHead(TVector<uint8_t> &InOutAssetFileData, uint64_t InOldHeadSize, const SAssetHead &InOutNewHead)
{
    TVector<uint8_t> NewAssetHeadData=AnyThreadSaveAssetHead(InOutNewHead);

    TVector<uint8_t> NewAssetFileData;

    CBinarySerializer BinarySerializer(NewAssetFileData);

    //1.写入头大小
    uint64_t NewHeadSize=NewAssetHeadData.Num()+sizeof(uint64_t);
    BinarySerializer<<NewHeadSize;

    //2.写入头内容
    NewAssetFileData.Append(NewAssetHeadData);

    //3.写入非头部分
    {
        TVector<uint8_t> OldAssetContent=
            InOutAssetFileData.Slice(
                InOldHeadSize
                ,InOutAssetFileData.Num());

        NewAssetFileData.Append(OldAssetContent);
    }

    InOutAssetFileData=std::move(NewAssetFileData);

    return NewHeadSize;
}

